package net.ib.mtalk.network.pipeline;

import javax.net.ssl.SSLEngine;

import net.ib.mtalk.constant.MTalkConstant;
import net.ib.mtalk.constant.NetworkConstant.Session;
import net.ib.mtalk.global.GlobalApplication;

import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.handler.ssl.SslHandler;

import android.content.Context;
import android.os.PowerManager;

public class TcpClientPipelineFactory implements ChannelPipelineFactory {

	private NetClientChannelHandler mChannelHandler;
	private PowerManager.WakeLock mWakeLock;

	public TcpClientPipelineFactory(NetClientChannelHandler channelHandler) {
		mChannelHandler = channelHandler;
		Context appContext = GlobalApplication.getContext();
		if(appContext != null) {
			mWakeLock = ((PowerManager)GlobalApplication.getContext().getSystemService(
					Context.POWER_SERVICE)).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
							MTalkConstant.TAG);
		}
	}

	/**
	 * 이 함수는 채널 데이터의 처리에 사용할 파이프 라인을 리턴해야 한다.
	 * @see org.jboss.netty.channel.ChannelPipelineFactory#getPipeline()
	 */
	public ChannelPipeline getPipeline() {
		ChannelPipeline cPipeline = Channels.pipeline();
		// 레이어가 배치되는 순서에 주의.
		// 위에서 아래로 가면서 [연결->디코딩->앱](Upstream)이 되고, 아래서 위로 가면서 [앱->인코딩->연결](Downstream)이 된다.
		// 연결에 가까운 레이어를 위에, 앱에 가까운 레이어를 아래에 배치

		if (Session.USE_TLS_SSL) {
			SSLEngine engine = SslContextFactory.getClientContext().createSSLEngine();
			engine.setUseClientMode(true);
			cPipeline.addLast("SslHandler", new SslHandler(engine));
		}

		// [스트림] = [buffer.length] + [buffer]
		cPipeline.addLast("StreamBufferDecoder", new StreamBufferDecoder(mWakeLock));	// Stream -> ChannelBuffer
		cPipeline.addLast("BufferStreamEncoder", new BufferStreamEncoder(mWakeLock));	// ChannelBuffer -> Stream
		// Envelope은 모든 메시지를 바이트 배열로 들고 있는 GPB 객체이다.
		cPipeline.addLast("EnvelopeBicoder", new EnvelopeBicoder(mWakeLock));	// Envelope <-> ChannelBuffer
		// TcpEnvelope에는 메시지를 객체로 들고 있으며, 상태나 콜백 등의 컨트롤 정보가 더 붙어있다.
		cPipeline.addLast("TcpEnvelopeBicoder", new TcpEnvelopeBicoder(mWakeLock));	// TcpEnvelope <-> Envelope

		cPipeline.addLast("TcpClientChannelHandler", mChannelHandler);

		return cPipeline;
	}

}
